/*
permutationIterator:  Fancy iterator, this iterator takes two collections
                      one for an elements and the other for an indexes,
                      the element returned from a dereference stay in
                      the indexed position from index collection
    Copyright (C) 2012  Jorge E. A. Atala
                        FuDePAN
    This file is part of the Fui Proyect.

    Fui is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Fui is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Fui.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef PERMUTATION_ITERATOR_IMP
#   error This is an internal file, do not include. Include permutationIterator.h instead.
#else
namespace fui
{
template<class ElementIterator, class IndexIterator>
PermutationIterator<ElementIterator, IndexIterator>::PermutationIterator(const ElementIterator& it, const IndexIterator& index)
    :   it(it),
        index(index)
{}

template<class ElementIterator, class IndexIterator>
typename PermutationIterator<ElementIterator, IndexIterator>::Element PermutationIterator<ElementIterator, IndexIterator>::operator*() const
{
    return *(it + *index);
}

template<class ElementIterator, class IndexIterator>
PermutationIterator<ElementIterator, IndexIterator> PermutationIterator<ElementIterator, IndexIterator>::operator+(const size_t ind) const
{
    return PermutationIterator<ElementIterator, IndexIterator>(it, index + ind);
}

template<class ElementIterator, class IndexIterator>
PermutationIterator<ElementIterator, IndexIterator> PermutationIterator<ElementIterator, IndexIterator>::operator-(const size_t ind) const
{
    return PermutationIterator<ElementIterator, IndexIterator>(it, index - ind);
}

template<class ElementIterator, class IndexIterator>
PermutationIterator<ElementIterator, IndexIterator> PermutationIterator<ElementIterator, IndexIterator>::operator-(const PermutationIterator<ElementIterator, IndexIterator> other) const
{
    return PermutationIterator<ElementIterator, IndexIterator>(index - other.index);
}

template<class ElementIterator, class IndexIterator>
PermutationIterator<ElementIterator, IndexIterator>& PermutationIterator<ElementIterator, IndexIterator>::operator++()
{
    ++index;
    return *this;
}

template<class ElementIterator, class IndexIterator>
PermutationIterator<ElementIterator, IndexIterator>& PermutationIterator<ElementIterator, IndexIterator>::operator--()
{
    --index;
    return *this;
}
template<class ElementIterator, class IndexIterator>
PermutationIterator<ElementIterator, IndexIterator> PermutationIterator<ElementIterator, IndexIterator>::operator++(const int)
{
    PermutationIterator<ElementIterator, IndexIterator> output(it, index++);
    return output;
}

template<class ElementIterator, class IndexIterator>
PermutationIterator<ElementIterator, IndexIterator> PermutationIterator<ElementIterator, IndexIterator>::operator--(const int)
{
    PermutationIterator<ElementIterator, IndexIterator> output(it, index--);
    return output;
}

template<class ElementIterator, class IndexIterator>
bool PermutationIterator<ElementIterator, IndexIterator>::operator==(const PermutationIterator<ElementIterator, IndexIterator>& other)const
{
    return (index == other.index) && (it == other.it);
}

template<class ElementIterator, class IndexIterator>
bool PermutationIterator<ElementIterator, IndexIterator>::operator!=(const PermutationIterator<ElementIterator, IndexIterator>& other)const
{
    return (index != other.index) && (it == other.it);
}

template<class ElementIterator, class IndexIterator>
bool PermutationIterator<ElementIterator, IndexIterator>::operator<(const PermutationIterator<ElementIterator, IndexIterator>& other)const
{
    return it + (*index) < other.it + (*(other.index));
}
}
#endif
